home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 10
/
The PC-Sig Library - Shareware for the IBM PC and Compatibles (PC-SIG)(Tenth Edition Disks 1-2804)(1991).iso
/
PC_SIGCD
/
02
/
8
/
DISK0285.ZIP
/
ASMBASIC.ASM
next >
Wrap
Assembly Source File
|
1984-06-18
|
8KB
|
279 lines
COMMENT *
CLUBware (tm)
ASMBASIC interfaces assembly language subroutines to the BASIC
interpreter.
Copyright 1984 Rayhawk Automation N.W. Inc
P.O. Box 1427
Beaverton, Oregon 97075
Method:
1) Our Basic code calls the service routines directly
CALL QPRINT ( FLAG% , STRING )
2) The flag indicates whether we are interpreted or compiled
3) Compiled code has the object code for QPRINT linked into it
4) Interpreted code has a separate module resident below
the BASIC interpreter (this module contains QPRINT)
5) Both the interpreted Basic code and the compiled Basic code
use an initialization routine to determine whether
currently running compiled or interpreted and sets global
variable, FLAG, accordingly
6) If compiled, basic initialization routine does nothing
7) If interpreted, initialization routine performs following
steps
A) Insert two instruction assembly language subroutine
into variable SUBINIT
Two instructions are INT 67h
RET 2
B) Make the following assignments
SEGVALUE% = 0
QPRINT% = 1
ZPRINT% = 2
CLREOL% = 3
SHELSORT% = 4
etc
(Everyone concerned with this project will agree on an
ordering and use it consistently.)
C) Make repeated calls to SUBINIT
CALL SUBINIT ( SEGVALUE% )
CALL SUBINIT ( QPRINT% )
CALL SUBINIT ( ZPRINT% )
CALL SUBINIT ( CLREOL% )
CALL SUBINIT ( SHELSORT% )
D) Use the Basic DEFSEG to make our subroutines addressable
DEFSEG = SEGVALUE%
E) Return from initialization
F) Implied but not stated is that after return from SUBINIT
the variable QPRINT% no longer contains 1 but the
offset within SEGVALUE% where the QPRINT% subroutine
can be found. Same for other subroutines
*
CODE SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:STACK
;_______________________________________________________________________________
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | INT 67h interrupt routine |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
EXTRN QPRINT:FAR
EXTRN SCRLDN:FAR
EXTRN SCRLUP:FAR
EXTRN XREP:FAR
EXTRN YREP:FAR
EXTRN CLREOL:FAR
EXTRN CLREOS:FAR
EXTRN ZPRINT:FAR
; EXTRN STDIN:FAR
; EXTRN STDOUT:FAR
TABLE_LEN LABEL WORD
DW 8 ; eight subroutines so far
DW 5252h ; tag to allow basic to make sure
; ASMBASIC is resident
; entry point for assembly SUBINT routine
SUBINIT PROC FAR
JMP SHORT SUB_CODE
SUBROUTINE_TABLE LABEL WORD ; table of subroutine offsets
DW OFFSET BAD_CALL ; 0
DW OFFSET QPRINT ; 1
DW OFFSET SCRLDN ; 2
DW OFFSET SCRLUP ; 3
DW OFFSET XREP ; 4
DW OFFSET YREP ; 5
DW OFFSET CLREOL ; 6
DW OFFSET CLREOS ; 7
DW OFFSET ZPRINT ; 8
; DW OFFSET STDIN ; 9
; DW OFFSET STDOUT ; 10
ARG EQU WORD PTR [BP+12] ; argument to SUBINIT
SUB_CODE:
PUSH BP ; address the argument
MOV BP,SP
MOV SI,ARG ; load the address of the argument
MOV AX,WORD PTR [SI] ; load the argument itself
; argument of 0 means return code segment for use in DEFSEG statement
CMP AX,0 ; return segment?
JA PREP_SUB
MOV AX,SEG CODE ; get our segment
MOV WORD PTR DS:[SI],AX ; return it to caller
JMP FAR PTR SUBINIT_DONE
PREP_SUB:
; non-zero argument means return offset of that subroutine
CMP AX,TABLE_LEN
JBE GOOD_ARGUMENT
CALL FAR PTR BAD_CALL ; let user know a bad call
MOV AX,0 ; has been made
GOOD_ARGUMENT:
SHL AX,1 ; each table entry is 2 bytes long
MOV BX,AX
MOV AX,SUBROUTINE_TABLE[BX] ; load subroutine offset
MOV WORD PTR DS:[SI],AX ; return offset to caller
; initialization complete, return to caller
; stack is cleared by code within basic segment
SUBINIT_DONE:
POP BP
IRET
SUBINIT ENDP
;_______________________________________________________________________________
BAD_MESSAGE LABEL BYTE
DB 10,13,'An invalid subroutine call was made to subinit.',10,13
DB 'There are only 8 subroutines defined within subinit.',10,13
DB 'A request was made for a subroutine outside of this range.'
DB 10,13,'$'
BAD_CALL PROC FAR
PUSH DS
MOV AX,SEG CODE
MOV DS,AX
MOV DX,OFFSET BAD_MESSAGE
MOV AH,09
INT 21h
POP DS
RET
BAD_CALL ENDP
;_______________________________________________________________________________
ASMBASIC PROC FAR
; Establish standard DOS linkage
PUSH DS ; Push addr of Program Segment Prefix
XOR AX,AX ; Zero AX
PUSH AX ; Push zero onto stack
; (offset of INT 20 within PSF)
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | take over the INT 67h |
; | interrupt if not already done |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
MOV DS,AX ; address low memory
LDS BX,DWORD PTR DS:[019Ch] ; load interrupt vector for int 67
MOV AX,WORD PTR SUBINIT
CMP AX,WORD PTR DS:[BX]
JNE NOT_HERE_YET
MOV AX,WORD PTR SUBINIT+2
CMP AX,WORD PTR DS:[BX+2]
JNE NOT_HERE_YET
MOV AX,WORD PTR SUBINIT+4
CMP AX,WORD PTR DS:[BX+4]
JNE NOT_HERE_YET
MOV AX,WORD PTR SUBINIT+6
CMP AX,WORD PTR DS:[BX+6]
JNE NOT_HERE_YET
JMP SHORT ALREADY_RESIDENT
NOT_HERE_YET:
MOV AX,SEG ASMBASIC ; Move our code segment
MOV DS,AX ; to the data segment register
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | take over the INT 67h |
; | interrupt |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
MOV DX,OFFSET SUBINIT ; Load offset of interrupt service mod
MOV AX,2567h ; Prepare for DOS service call type 25
; to establish service for INT 05
INT 21h ; Ask DOS to establish service
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | modify INT 20 into INT 27 in the |
; | program segment prefix |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
MOV BYTE PTR ES:[01],27h ; Change INT 20h to INT 27h
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | 6) load address of ending tag into DX |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
MOV AX,SEG BOTSTACK
SUB AX,SEG ASMBASIC
MOV CL,4 ; prepare for 4 bit shift
SHL AX,CL ; shift up (convert from seg to abs)
ADD AX,OFFSET BOTSTACK ; add address of bottom location
ADD AX,0103h ; Pad offset because DOS measures
; offset relative to Program
; Segment Prefix
MOV DX,AX ; leave where DOS will find it
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | 7) use RET FAR to return to DOS and |
; | leave service routine resident |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
ALREADY_RESIDENT:
RET
ASMBASIC ENDP
CODE ENDS
;_______________________________________________________________________________
STACK SEGMENT PARA STACK 'STACK'
BOTSTACK LABEL BYTE
DB 24 DUP('STACK***')
TOPSTACK DB 0
STACK ENDS
END ASMBASIC